package com.small.task;

import com.small.common.Const;
import com.small.common.RedissonManager;
import com.small.service.IOrderService;
import com.small.util.PropertiesUtil;
import com.small.util.RedisShradedPoolUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import java.util.concurrent.TimeUnit;

/**
 * 定时关闭订单，恢复商品库存
 *
 * @create: xie
 */
@Component
@Slf4j
public class CloseOrderTask {
    @Autowired
    private IOrderService iOrderService;
    @Autowired
    private RedissonManager redissonManager;


    //删除锁,tomcat关闭前会执行@PreDestroy方法
    @PreDestroy
    public void delLock() {
        RedisShradedPoolUtil.del(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);

    }

    //@Scheduled(cron = "0 */1 * * * ?") //每一分钟执行一次
    public void closeOrderTaskV1() {
        log.info("关闭订单定时任务启动");
        int hour = Integer.parseInt(PropertiesUtil.getProperty("close.order.task.time.hour", "2"));
        //iOrderService.closeOrder(hour);
        log.info("关闭订单定时任务关闭");
    }


    //@Scheduled(cron = "0 */1 * * * ?") //每一分钟执行一次
    public void closeOrderTaskV2() {
        log.info("关闭订单定时任务启动");
        long timeout = Integer.parseInt(PropertiesUtil.getProperty("lock.timeout", "5000"));
        Long setnxResult = RedisShradedPoolUtil.setnx(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK, String.valueOf(System.currentTimeMillis() + timeout));
        if (setnxResult != null && setnxResult.intValue() == 1) {
            //如果不为空，返回值为1，代表获取锁成功，0表示没有获取到
            closeOrder(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
        } else {
            //未获取到锁，继续判断，判断时间戳，看是否可以重置并获取到锁
            String lockValue = RedisShradedPoolUtil.get(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
            //如果当前时间超过锁的超时时间，重置并获取锁
            if (lockValue != null && System.currentTimeMillis() > Long.parseLong(lockValue)) {
                //用当前时间戳getset,返回旧的时间戳，当锁没有旧值，即表示key不存在，返回nil
                String getSetResult = RedisShradedPoolUtil.getSet(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK, String.valueOf(System.currentTimeMillis() + timeout));
                if (getSetResult == null || (getSetResult != null && StringUtils.equals(lockValue, getSetResult))) {
                    //真正获取到锁
                    closeOrder(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
                } else {
                    log.info("没有获取到分布式锁:{}", Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
                }
            } else {
                log.info("没有获取到分布式锁:{}", Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
            }
        }
        log.info("关闭订单定时任务关闭");
    }

    @Scheduled(cron = "0 */1 * * * ?") //每一分钟执行一次
    public void closeOrderTaskV3() {
        log.info("关闭订单定时任务启动");
        //生成锁
        RLock lock = redissonManager.getRedisson().getLock(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
        boolean getLock = false;
        try {
            //尝试获取锁，参数分别是，获取超时时间，自动解锁时间，时间单位
            if (lock.tryLock(0, 50, TimeUnit.SECONDS)) {
                getLock=true;
                log.info("Redisson获取到分布式锁:{}，ThreadName:{}", Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK, Thread.currentThread().getName());
                int hour = Integer.parseInt(PropertiesUtil.getProperty("close.order.task.time.hour", "2"));
                //iOrderService.closeOrder(hour);
            }else {
                log.info("Redisson没有获取分布式锁:{}，ThreadName:{}", Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK, Thread.currentThread().getName());
            }
        } catch (InterruptedException e) {
           log.error("Redisson分布式锁获取异常",e);
        }finally {
            if(!getLock){
                return;
            }
            lock.unlock();
            log.info("Redisson分布式锁释放");
        }
    }


    //设置锁的有效期，在有效期内执行关闭订单调度任务，然后删除锁（释放锁）
    private void closeOrder(String lockName) {
        RedisShradedPoolUtil.expire(lockName, 5);//有效期5秒 防止死锁
        log.info("获取{},ThreadName:{}", Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK, Thread.currentThread().getName());
        int hour = Integer.parseInt(PropertiesUtil.getProperty("close.order.task.time.hour", "2"));
        //iOrderService.closeOrder(hour);
        RedisShradedPoolUtil.del(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
        log.info("释放{},ThreadName:{}", Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK, Thread.currentThread().getName());
        log.info("============================================");
    }
}
